all repos — caroster @ efb618469130ae351c648f97b4a1d6cac23525b3

[Octree] Group carpool to your event https://caroster.io

frontend/pages/e/[uuid]/details.tsx (view raw)

  1import moment from 'moment';
  2import Button from '@mui/material/Button';
  3import Box from '@mui/material/Box';
  4import Link from '@mui/material/Link';
  5import Paper from '@mui/material/Paper';
  6import Container from '@mui/material/Container';
  7import TextField from '@mui/material/TextField';
  8import Typography from '@mui/material/Typography';
  9import {useTheme} from '@mui/material/styles';
 10import {DatePicker} from '@mui/x-date-pickers/DatePicker';
 11import {PropsWithChildren, useState} from 'react';
 12import {useTranslation} from 'react-i18next';
 13import pageUtils from '../../../lib/pageUtils';
 14import ShareEvent from '../../../containers/ShareEvent';
 15import useEventStore from '../../../stores/useEventStore';
 16import useToastStore from '../../../stores/useToastStore';
 17import useSettings from '../../../hooks/useSettings';
 18import EventLayout, {TabComponent} from '../../../layouts/Event';
 19import {
 20  EventByUuidDocument,
 21  useUpdateEventMutation,
 22} from '../../../generated/graphql';
 23import SupportCaroster from '../../../containers/SupportCaroster';
 24
 25interface Props {
 26  eventUUID: string;
 27  announcement?: string;
 28}
 29
 30const Page = (props: PropsWithChildren<Props>) => {
 31  return <EventLayout {...props} Tab={DetailsTab} />;
 32};
 33
 34const DetailsTab: TabComponent = ({}) => {
 35  const {t} = useTranslation();
 36  const theme = useTheme();
 37  const settings = useSettings();
 38  const [updateEvent] = useUpdateEventMutation();
 39  const addToast = useToastStore(s => s.addToast);
 40  const setEventUpdate = useEventStore(s => s.setEventUpdate);
 41  const event = useEventStore(s => s.event);
 42  const [isEditing, setIsEditing] = useState(false);
 43  const idPrefix = isEditing ? 'EditEvent' : 'Event';
 44
 45  const onSave = async e => {
 46    try {
 47      const {uuid, ...data} = event;
 48      const {id, travels, waitingPassengers, __typename, ...input} = data;
 49      await updateEvent({
 50        variables: {uuid, eventUpdate: input},
 51        refetchQueries: ['eventByUUID'],
 52      });
 53      setIsEditing(false);
 54    } catch (error) {
 55      console.error(error);
 56      addToast(t('event.errors.cant_update'));
 57    }
 58  };
 59  const sectionSx = {
 60    marginBottom: theme.spacing(2),
 61    width: '540px',
 62    maxWidth: '100%',
 63    paddingX: theme.spacing(2),
 64  };
 65
 66  const modifyButton = isEditing ? (
 67    <Button
 68      variant="contained"
 69      color="primary"
 70      sx={{position: 'absolute', right: theme.spacing(2)}}
 71      onClick={onSave}
 72    >
 73      {t('event.details.save')}
 74    </Button>
 75  ) : (
 76    <Button
 77      variant="text"
 78      color="primary"
 79      sx={{position: 'absolute', right: theme.spacing(2)}}
 80      onClick={() => setIsEditing(true)}
 81    >
 82      {t('event.details.modify')}
 83    </Button>
 84  );
 85
 86  if (!event) return null;
 87
 88  return (
 89    <Box
 90      sx={{
 91        position: 'relative',
 92        paddingLeft: '80px',
 93
 94        [theme.breakpoints.down('md')]: {
 95          paddingLeft: 0,
 96          paddingBottom: '80px',
 97        },
 98      }}
 99    >
100      <Container maxWidth="sm" sx={{marginTop: theme.spacing(6)}}>
101        <Paper sx={{position: 'relative', padding: theme.spacing(2)}}>
102          {modifyButton}
103          <Box sx={sectionSx}>
104            <Typography variant="h6">{t('event.fields.name')}</Typography>
105            {isEditing ? (
106              <TextField
107                fullWidth
108                value={event.name}
109                onChange={e => setEventUpdate({name: e.target.value})}
110                name="name"
111                id="EditEventName"
112              />
113            ) : (
114              <Typography variant="body1" id={`${idPrefix}Name`}>
115                {event.name ?? t('event.fields.empty')}
116              </Typography>
117            )}
118          </Box>
119          <Box sx={sectionSx}>
120            <Typography variant="h6">{t('event.fields.date')}</Typography>
121            {isEditing ? (
122              <DatePicker
123                renderInput={props => (
124                  <TextField
125                    {...props}
126                    id={`${idPrefix}Date`}
127                    fullWidth
128                    placeholder={t('event.fields.date_placeholder')}
129                  />
130                )}
131                inputFormat="DD/MM/yyyy"
132                value={event.date}
133                onChange={date =>
134                  setEventUpdate({
135                    date: !date ? null : moment(date).format('YYYY-MM-DD'),
136                  })
137                }
138              />
139            ) : (
140              <Typography variant="body1" id={`${idPrefix}Date`}>
141                {event.date
142                  ? moment(event.date).format('DD/MM/YYYY')
143                  : t('event.fields.empty')}
144              </Typography>
145            )}
146          </Box>
147          <Box sx={sectionSx}>
148            <Typography variant="h6">{t('event.fields.address')}</Typography>
149            {isEditing ? (
150              <TextField
151                fullWidth
152                multiline
153                maxRows={4}
154                inputProps={{maxLength: 250}}
155                helperText={`${event.address?.length ?? 0}/250`}
156                value={event.address}
157                onChange={e => setEventUpdate({address: e.target.value})}
158                id={`${idPrefix}Address`}
159                name="address"
160              />
161            ) : (
162              <Typography variant="body1" id={`${idPrefix}Address`}>
163                {event.address ? (
164                  <Link
165                    target="_blank"
166                    rel="noreferrer"
167                    href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(
168                      event.address
169                    )}`}
170                    onClick={e => e.preventDefault}
171                  >
172                    {event.address}
173                  </Link>
174                ) : (
175                  t('event.fields.empty')
176                )}
177              </Typography>
178            )}
179          </Box>
180          <Box sx={sectionSx}>
181            <Typography variant="h6">
182              {t('event.fields.description')}
183            </Typography>
184            {isEditing ? (
185              <TextField
186                fullWidth
187                multiline
188                maxRows={4}
189                inputProps={{maxLength: 250}}
190                helperText={`${event.description?.length || 0}/250`}
191                value={event.description || ''}
192                onChange={e => setEventUpdate({description: e.target.value})}
193                id={`${idPrefix}Description`}
194                name="description"
195              />
196            ) : (
197              <Typography variant="body1" id={`${idPrefix}Description`}>
198                {event.description ?? t('event.fields.empty')}
199              </Typography>
200            )}
201          </Box>
202          <Box sx={sectionSx}>
203            <Typography variant="h6">{t('event.fields.link')}</Typography>
204            <Typography>{t('event.fields.link_desc')}</Typography>
205          </Box>
206          <Box pt={4} pb={2} justifyContent="center" display="flex">
207            <ShareEvent title={`Caroster ${event.name}`} />{' '}
208          </Box>
209        </Paper>
210        <Box mt={4} display="flex" justifyContent="center">
211          <SupportCaroster />
212        </Box>
213      </Container>
214    </Box>
215  );
216};
217
218export const getServerSideProps = pageUtils.getServerSideProps(
219  async (context, apolloClient) => {
220    const {uuid} = context.query;
221    const {host = ''} = context.req.headers;
222    let event = null;
223
224    // Fetch event
225    try {
226      const {data} = await apolloClient.query({
227        query: EventByUuidDocument,
228        variables: {uuid},
229      });
230      event = data?.eventByUUID?.data;
231    } catch (error) {
232      return {
233        notFound: true,
234      };
235    }
236
237    return {
238      props: {
239        eventUUID: uuid,
240        metas: {
241          title: event?.attributes?.name || '',
242          url: `https://${host}${context.resolvedUrl}`,
243        },
244      },
245    };
246  }
247);
248export default Page;